package com.cmict.data.bpm.service.task;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HtmlUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cmict.data.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO;
import com.cmict.data.bpm.dal.dataobject.externalfile.ExternalFileDO;
import com.cmict.data.bpm.dal.dataobject.task.BpmProcessInstanceExtDO;
import com.cmict.data.bpm.service.externalfile.ExternalFileCreateBO;
import com.cmict.data.bpm.service.externalfile.ExternalFileInfo;
import com.cmict.data.bpm.service.externalfile.ExternalFileService;
import com.cmict.data.form.api.task.FormDataApi;
import com.cmict.data.form.api.task.dto.SysFormDTO;
import com.cmict.data.framework.common.pojo.CommonResult;
import com.cmict.data.framework.common.pojo.PageResult;
import com.cmict.data.framework.common.util.collection.CollectionUtils;
import com.cmict.data.framework.common.util.number.NumberUtils;
import com.cmict.data.framework.common.util.object.PageUtils;
import com.cmict.data.bpm.controller.admin.task.vo.task.*;
import com.cmict.data.bpm.convert.task.BpmTaskConvert;
import com.cmict.data.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
import com.cmict.data.bpm.dal.dataobject.externalfile.ExternalFileDO;
import com.cmict.data.bpm.dal.dataobject.task.BpmProcessInstanceExtDO;
import com.cmict.data.bpm.dal.dataobject.task.BpmTaskExtDO;
import com.cmict.data.bpm.dal.mysql.definition.BpmProcessDefinitionExtMapper;
import com.cmict.data.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper;
import com.cmict.data.bpm.dal.mysql.task.BpmActivityMapper;
import com.cmict.data.bpm.dal.mysql.task.BpmProcessInstanceExtMapper;
import com.cmict.data.bpm.dal.mysql.task.BpmTaskExtMapper;
import com.cmict.data.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum;
import com.cmict.data.bpm.enums.task.BpmProcessInstanceResultEnum;
import com.cmict.data.bpm.service.externalfile.ExternalFileCreateBO;
import com.cmict.data.bpm.service.externalfile.ExternalFileInfo;
import com.cmict.data.bpm.service.externalfile.ExternalFileService;
import com.cmict.data.bpm.service.message.BpmMessageService;
import com.cmict.data.framework.common.pojo.PageResult;
import com.cmict.data.framework.common.util.date.DateUtils;
import com.cmict.data.framework.common.util.number.NumberUtils;
import com.cmict.data.framework.common.util.object.PageUtils;
import com.cmict.data.system.api.dept.DeptApi;
import com.cmict.data.system.api.dept.dto.DeptRespDTO;
import com.cmict.data.system.api.user.AdminUserApi;
import com.cmict.data.system.api.user.dto.AdminUserRespDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.HistoryService;
import org.flowable.engine.ManagementService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.api.history.HistoricTaskInstanceQuery;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.cmict.data.bpm.enums.ErrorCodeConstants.*;
import static com.cmict.data.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.cmict.data.framework.common.util.collection.CollectionUtils.convertMap;
import static com.cmict.data.framework.common.util.collection.CollectionUtils.convertSet;

/**
 * 流程任务实例 Service 实现类
 *
 * @author awesome
 * @author jason
 */
@Slf4j
@Service
public class BpmTaskServiceImpl implements BpmTaskService {

    @Resource
    private TaskService taskService;
    @Resource
    private HistoryService historyService;

    @Resource
    private BpmProcessInstanceService processInstanceService;
    @Resource
    private AdminUserApi adminUserApi;
    @Resource
    private FormDataApi formDataApi;
    @Resource
    private DeptApi deptApi;
    @Resource
    private BpmTaskExtMapper taskExtMapper;
    @Resource
    private BpmMessageService messageService;
    @Resource
    private BpmProcessDefinitionExtMapper processDefinitionExtMapper;
    @Resource
    private BpmProcessInstanceExtMapper processInstanceExtMapper;
    @Resource
    private ManagementService managementService;
    @Resource
    private BpmTaskAssignRuleMapper taskAssignRuleMapper;
    @Resource
    private BpmActivityMapper bpmActivityMapper;
    @Resource
    private ExternalFileService externalFileService;
    @Override
    public PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageVO) {

        // 查询待办任务
        TaskQuery taskQuery = taskService.createTaskQuery().taskAssignee(String.valueOf(userId)) // 分配给自己
                .orderByTaskCreateTime().desc(); // 创建时间倒序
        if (StrUtil.isNotBlank(pageVO.getName())) {
            taskQuery.taskNameLike("%" + pageVO.getName() + "%");
        }
        if (pageVO.getBeginCreateTime() != null) {
            taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getBeginCreateTime()));
        }
        if (pageVO.getEndCreateTime() != null) {
            taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getEndCreateTime()));
        }
        if (StringUtils.isNotBlank(pageVO.getProcessDefinitionName())) {
            taskQuery.processDefinitionName(pageVO.getProcessDefinitionName());
        }

        if (ObjectUtil.isNotNull(pageVO.getProcessDefinitionKeys()) && pageVO.getProcessDefinitionKeys().size() > 0) {
            taskQuery.processDefinitionKeyIn(pageVO.getProcessDefinitionKeys());
        }
        // 执行查询
        List<Task> tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize());
        if (CollUtil.isEmpty(tasks)) {
            return PageResult.empty(taskQuery.count());
        }

        // 获得 ProcessInstance Map
        Map<String, ProcessInstance> processInstanceMap =
                processInstanceService.getProcessInstanceMap(convertSet(tasks, Task::getProcessInstanceId));

        Map<String, BpmProcessInstanceExtDO> processInstanceExtMap =
                processInstanceService.getProcessInstanceExtMap(convertSet(tasks, Task::getProcessInstanceId));

        // 获得 User Map
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMapByIdsJoin(
                convertSet(processInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId())));
        List<BpmTaskTodoPageItemRespVO> list = BpmTaskConvert.INSTANCE.convertList4(tasks, processInstanceMap,processInstanceExtMap, userMap);
        if(list.size() > 0){
            for (int i = 0 ; i < list.size() ; i++ ){
                if(null != list.get(i).getProcessInstance()){
                    String processDefinitionId = list.get(i).getProcessInstance().getProcessDefinitionId();
                    Integer formRecordId = list.get(i).getFormRecordId();
                    BpmProcessDefinitionExtDO bpmProcessDefinitionExtDO = processDefinitionExtMapper.selectByProcessDefinitionId(processDefinitionId);
                    if(null != bpmProcessDefinitionExtDO && null != bpmProcessDefinitionExtDO.getFormId() && null != formRecordId){
                        CommonResult resultData = formDataApi.getDataByIds(formRecordId,bpmProcessDefinitionExtDO.getFormId());
                        if(resultData.getCode() == 0 && null != resultData.getData()){
                            Map<Object,Object> data = (Map<Object, Object>) resultData.getData();
                            if(data.containsKey("data_id")){
                                list.get(i).setDataId((Integer)data.get("data_id"));
                            }
                            if(data.containsKey("version_id")){
                                list.get(i).setVersionId((Integer)data.get("version_id"));
                            }
                        }
                        SysFormDTO form = formDataApi.getSysFormById(bpmProcessDefinitionExtDO.getFormId());
                        if( null != form ){
                            list.get(i).setTableName(form.getTableName());
                            list.get(i).setFormJsonMessage(form.getFormJsonMessage());
                        }
                    }
                }
            }
        }
        // 拼接结果
        return new PageResult<>(list, taskQuery.count());
    }

    @Override
    public List<BpmTaskTodoPageItemRespVO> getTodoTask(Long userId, Long formId) {
        // 查询待办任务
        TaskQuery taskQuery = taskService.createTaskQuery().taskAssignee(String.valueOf(userId)) // 分配给自己的任务
                .orderByTaskCreateTime().desc(); // 创建时间倒序
        List<Task> tasks = taskQuery.list();
        if (CollUtil.isEmpty(tasks)) {
            return CollUtil.newArrayList();
        }
        Set<String> defineIds = processDefinitionExtMapper.getDefineIdsByFormId(formId);
        if (CollUtil.isNotEmpty(defineIds)) {
            tasks = tasks.stream().filter(item-> defineIds.contains(item.getProcessDefinitionId())).collect(Collectors.toList());
        }
        Map<String, BpmProcessInstanceExtDO> processInstanceExtMap =
                processInstanceService.getProcessInstanceExtMap(convertSet(tasks, Task::getProcessInstanceId));
        List<BpmTaskTodoPageItemRespVO> itemRespVOS = BpmTaskConvert.INSTANCE.convertList(tasks, processInstanceExtMap);
        return itemRespVOS;
    }

    @Override
    public PageResult<BpmTaskDonePageItemRespVO> getDoneTaskPage(Long userId, BpmTaskDonePageReqVO pageVO) {
        // 查询已办任务
        HistoricTaskInstanceQuery taskQuery = historyService.createHistoricTaskInstanceQuery().finished() // 已完成
                //.taskAssignee(String.valueOf(userId)) // 分配给自己
                .orderByHistoricTaskInstanceEndTime().desc(); // 审批时间倒序
        if (userId != 0 ) {
            taskQuery.taskAssignee(String.valueOf(userId));
        }
        if (StrUtil.isNotBlank(pageVO.getName())) {
            taskQuery.taskNameLike("%" + pageVO.getName() + "%");
        }
        if (pageVO.getBeginCreateTime() != null) {
            taskQuery.taskCreatedAfter(DateUtils.of(pageVO.getBeginCreateTime()));
        }
        if (pageVO.getEndCreateTime() != null) {
            taskQuery.taskCreatedBefore(DateUtils.of(pageVO.getEndCreateTime()));
        }
        if (StrUtil.isNotBlank(pageVO.getProcessDefinitionKey())) {
            taskQuery.processDefinitionKey(pageVO.getProcessDefinitionKey());
        }
        if (ObjectUtil.isNotNull(pageVO.getProcessDefinitionKeys()) && pageVO.getProcessDefinitionKeys().size() > 0) {
            taskQuery.processDefinitionKeyIn(pageVO.getProcessDefinitionKeys());
        }
        // 执行查询
        List<HistoricTaskInstance> tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize());
        if (CollUtil.isEmpty(tasks)) {
            return PageResult.empty(taskQuery.count());
        }

        // 获得 TaskExtDO Map
        List<BpmTaskExtDO> bpmTaskExtDOs =
                taskExtMapper.selectListByTaskIds(convertSet(tasks, HistoricTaskInstance::getId));
        Map<String, BpmTaskExtDO> bpmTaskExtDOMap = convertMap(bpmTaskExtDOs, BpmTaskExtDO::getTaskId);
        // 获得 ProcessInstance Map
        Map<String, HistoricProcessInstance> historicProcessInstanceMap =
                processInstanceService.getHistoricProcessInstanceMap(
                        convertSet(tasks, HistoricTaskInstance::getProcessInstanceId));

        Map<String, BpmProcessInstanceExtDO> processInstanceExtMap =
                processInstanceService.getProcessInstanceExtMap(convertSet(tasks, HistoricTaskInstance::getProcessInstanceId));

        // 获得 User Map
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMapByIdsJoin(
                convertSet(historicProcessInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId())));
        List<BpmTaskDonePageItemRespVO> list = BpmTaskConvert.INSTANCE.convertList5(tasks, bpmTaskExtDOMap, historicProcessInstanceMap,processInstanceExtMap, userMap);
        if(list.size() > 0){
            for (int i = 0 ; i < list.size() ; i++ ){
                if(null != list.get(i).getProcessInstance()){
                    String processDefinitionId = list.get(i).getProcessInstance().getProcessDefinitionId();
                    Integer formRecordId = list.get(i).getFormRecordId();
                    BpmProcessDefinitionExtDO bpmProcessDefinitionExtDO = processDefinitionExtMapper.selectByProcessDefinitionId(processDefinitionId);
                    if(null != bpmProcessDefinitionExtDO && null != bpmProcessDefinitionExtDO.getFormId() && null != formRecordId){
                        CommonResult resultData = formDataApi.getDataByIds(formRecordId,bpmProcessDefinitionExtDO.getFormId());
                        if(resultData.getCode() == 0 && null != resultData.getData()){
                            Map<Object,Object> data = (Map<Object, Object>) resultData.getData();
                            if(data.containsKey("data_id")){
                                list.get(i).setDataId((Integer)data.get("data_id"));
                            }
                            if(data.containsKey("version_id")){
                                list.get(i).setVersionId((Integer)data.get("version_id"));
                            }
                        }
                        SysFormDTO form = formDataApi.getSysFormById(bpmProcessDefinitionExtDO.getFormId());
                        if( null != form ){
                            list.get(i).setTableName(form.getTableName());
                            list.get(i).setFormJsonMessage(form.getFormJsonMessage());
                        }
                    }
                }
            }
        }
        // 拼接结果
        return new PageResult<>(list, taskQuery.count());
    }

    @Override
    public List<BpmTaskDonePageItemRespVO> getDoneTask(Long userId, Long formId) {
        // 查询已办任务n
        HistoricTaskInstanceQuery taskQuery = historyService.createHistoricTaskInstanceQuery().finished() // 已完成
                //.taskAssignee(String.valueOf(userId)) // 分配给自己
                .orderByHistoricTaskInstanceEndTime().desc(); // 审批时间倒序
        if (userId != 0 ) {
            taskQuery.taskAssignee(String.valueOf(userId));
        }
        // 执行查询
        if (userId != 0 ) {
            taskQuery.taskAssignee(String.valueOf(userId));
        }
        List<HistoricTaskInstance> tasks = taskQuery.list();
        if (CollUtil.isEmpty(tasks)) {
            return CollUtil.newArrayList();
        }
        Set<String> defineIds = processDefinitionExtMapper.getDefineIdsByFormId(formId);
        if (CollUtil.isNotEmpty(defineIds)) {
            tasks = tasks.stream().filter(item-> defineIds.contains(item.getProcessDefinitionId())).collect(Collectors.toList());
        }
        // 获得 TaskExtDO Map
        List<BpmTaskExtDO> bpmTaskExtDOs =
                taskExtMapper.selectListByTaskIds(convertSet(tasks, HistoricTaskInstance::getId));
        Map<String, BpmTaskExtDO> bpmTaskExtDOMap = convertMap(bpmTaskExtDOs, BpmTaskExtDO::getTaskId);
        // 获得 ProcessInstance Map
        Map<String, HistoricProcessInstance> historicProcessInstanceMap =
                processInstanceService.getHistoricProcessInstanceMap(
                        convertSet(tasks, HistoricTaskInstance::getProcessInstanceId));
        Map<String, BpmProcessInstanceExtDO> processInstanceExtMap =
                processInstanceService.getProcessInstanceExtMap(convertSet(tasks, HistoricTaskInstance::getProcessInstanceId));
        // 获得 User Map
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMapByIdsJoin(
                convertSet(historicProcessInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId())));
        // 拼接结果
        return BpmTaskConvert.INSTANCE.convertList5(tasks, bpmTaskExtDOMap, historicProcessInstanceMap, processInstanceExtMap, userMap);
    }

    @Override
    public List<Task> getTasksByProcessInstanceIds(List<String> processInstanceIds) {
        if (CollUtil.isEmpty(processInstanceIds)) {
            return Collections.emptyList();
        }
        return taskService.createTaskQuery().processInstanceIdIn(processInstanceIds).list();
    }

    @Override
    public List<BpmTaskRespVO> getTaskListByProcessInstanceId(String processInstanceId) {
        // 获得任务列表
        List<HistoricTaskInstance> tasks = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(processInstanceId)
                .orderByHistoricTaskInstanceStartTime().desc() // 创建时间倒序
                .list();
        if (CollUtil.isEmpty(tasks)) {
            return Collections.emptyList();
        }
        // 获得 TaskExtDO Map
        List<BpmTaskExtDO> bpmTaskExtDOs = taskExtMapper.selectListByTaskIds(convertSet(tasks, HistoricTaskInstance::getId));
        Map<String, BpmTaskExtDO> bpmTaskExtDOMap = convertMap(bpmTaskExtDOs, BpmTaskExtDO::getTaskId);
        // 获得 ProcessInstance Map
        HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(processInstanceId);
        // 获得 User Map
        Set<Long> userIds = convertSet(tasks, task -> NumberUtils.parseLong(task.getAssignee()));
        userIds.add(NumberUtils.parseLong(processInstance.getStartUserId()));
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMapByIdsJoin(userIds);
        // 获得 Dept Map
        Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMapBySetIds(convertSet(userMap.values(), AdminUserRespDTO::getDeptId));
        //获取附件
        List<ExternalFileDO> externalFileList = externalFileService.getExternalFileList(processInstanceId);
        // 拼接数据
        return BpmTaskConvert.INSTANCE.convertList3(tasks, bpmTaskExtDOMap, processInstance, userMap, deptMap, externalFileList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void approveTask(Long userId, @Valid BpmTaskApproveReqVO reqVO) {
        // 校验任务存在
        Task task = checkTask(userId, reqVO.getId());
        // 校验流程实例存在
        ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
        if (instance == null) {
            throw exception(PROCESS_INSTANCE_NOT_EXISTS);
        }
        reqVO.setReason(HtmlUtil.filter(reqVO.getReason()));
        if (ObjectUtil.isNotNull(task.getAssignee())) {
            taskService.setAssignee(task.getId(), String.valueOf(userId));
        }
        // 完成任务，审批通过
        taskService.complete(task.getId(), instance.getProcessVariables());
        // 如果有审批附近，保存附件
        createExternalFile(reqVO.getId(), instance.getProcessInstanceId(),reqVO.getFileList(),reqVO.getImageList());
        // 更新任务拓展表为通过
        taskExtMapper.updateByTaskId(
                new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.APPROVE.getResult())
                        .setReason(reqVO.getReason()));
        // 判断任务是否为或签，或签时删除其余不用审批的任务
        List<BpmTaskAssignRuleDO> bpmTaskAssignRuleList =
                taskAssignRuleMapper.selectListByProcessDefinitionId(task.getProcessDefinitionId(),
                        task.getTaskDefinitionKey());
    }

    @Override
    public void autoApproveTask(Long userId, @Valid BpmTaskApproveReqVO reqVO) {
        // 校验任务存在
        Task task = checkTask(userId, reqVO.getId());
        // 校验流程实例存在
        ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
        if (instance == null) {
            throw exception(PROCESS_INSTANCE_NOT_EXISTS);
        }
        if (ObjectUtil.isNotNull(task.getAssignee())) {
            taskService.setAssignee(task.getId(), String.valueOf(userId));
        }
        // 完成任务，审批通过
        taskService.complete(task.getId(), instance.getProcessVariables());
        // 如果有审批附近，保存附件
        createExternalFile(reqVO.getId(), instance.getProcessInstanceId(),reqVO.getFileList(),reqVO.getImageList());
        // 更新任务拓展表为通过
        taskExtMapper.updateByTaskId(
                new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.APPROVE.getResult())
                        .setReason(reqVO.getReason()));
        // 判断任务是否为或签，或签时删除其余不用审批的任务
        List<BpmTaskAssignRuleDO> bpmTaskAssignRuleList =
                taskAssignRuleMapper.selectListByProcessDefinitionId(task.getProcessDefinitionId(),
                        task.getTaskDefinitionKey());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchApproveTask(Long userId, @Valid BpmTaskApproveReqVO reqVO) {
        for (String id : reqVO.getIdList()) {
            reqVO.setId(id);
            // 校验任务存在
            Task task = checkTask(userId, reqVO.getId());
            // 校验流程实例存在
            ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
            if (instance == null) {
                throw exception(PROCESS_INSTANCE_NOT_EXISTS);
            }
            reqVO.setReason(HtmlUtil.filter(reqVO.getReason()));
            if (ObjectUtil.isNotNull(task.getAssignee())) {
                taskService.setAssignee(task.getId(), String.valueOf(userId));
            }
            // 完成任务，审批通过
            taskService.complete(task.getId(), instance.getProcessVariables());
            // 如果有审批附近，保存附件
            createExternalFile(reqVO.getId(), instance.getProcessInstanceId(),reqVO.getFileList(),reqVO.getImageList());
            // 更新任务拓展表为通过
            taskExtMapper.updateByTaskId(
                    new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.APPROVE.getResult())
                            .setReason(reqVO.getReason()));
            // 判断任务是否为或签，或签时删除其余不用审批的任务
            List<BpmTaskAssignRuleDO> bpmTaskAssignRuleList =
                    taskAssignRuleMapper.selectListByProcessDefinitionId(task.getProcessDefinitionId(),
                            task.getTaskDefinitionKey());

        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void rejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO) {
        Task task = checkTask(userId, reqVO.getId());
        // 校验流程实例存在
        ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
        if (instance == null) {
            throw exception(PROCESS_INSTANCE_NOT_EXISTS);
        }
        reqVO.setReason(HtmlUtil.filter(reqVO.getReason()));
        // 更新流程实例为不通过
        processInstanceService.updateProcessInstanceExtReject(instance.getProcessInstanceId(), reqVO.getReason());
        // 如果有审批附近，保存附件
        createExternalFile(reqVO.getId(), instance.getProcessInstanceId(),reqVO.getFileList(),reqVO.getImageList());
        // 更新任务拓展表为不通过
        taskExtMapper.updateByTaskId(
                new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.REJECT.getResult())
                        .setReason(reqVO.getReason()));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchRejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO) {
        for (String id : reqVO.getIdList()) {
            reqVO.setId(id);
            Task task = checkTask(userId, reqVO.getId());
            // 校验流程实例存在
            ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
            if (instance == null) {
                throw exception(PROCESS_INSTANCE_NOT_EXISTS);
            }
            reqVO.setReason(HtmlUtil.filter(reqVO.getReason()));
            // 更新流程实例为不通过
            processInstanceService.updateProcessInstanceExtReject(instance.getProcessInstanceId(), reqVO.getReason());
            // 如果有审批附近，保存附件
            createExternalFile(reqVO.getId(), instance.getProcessInstanceId(),reqVO.getFileList(),reqVO.getImageList());
            // 更新任务拓展表为不通过
            taskExtMapper.updateByTaskId(
                    new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.REJECT.getResult())
                            .setReason(reqVO.getReason()));
        }

    }

    @Override
    public void updateTaskAssignee(Long userId, BpmTaskUpdateAssigneeReqVO reqVO) {
        // 校验任务存在
        Task task = checkTask(userId, reqVO.getId());
        ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
        if (instance == null) {
            throw exception(PROCESS_INSTANCE_NOT_EXISTS);
        }
        reqVO.setReason(HtmlUtil.filter(reqVO.getReason()));
        // 如果有审批附近，保存附件
        createExternalFile(reqVO.getId(), instance.getProcessInstanceId(),reqVO.getFileList(),reqVO.getImageList());
        // 更新负责人
        updateTaskAssignee(task.getId(), reqVO.getAssigneeUserId());
        // 更新任务拓展表为不通过
        taskExtMapper.updateByTaskId(
                new BpmTaskExtDO().setTaskId(task.getId()).setReason(reqVO.getReason()));
    }


    @Override
    public void batchUpdateTaskAssignee(Long userId, @Valid BpmTaskUpdateAssigneeReqVO reqVO) {
        for (String id : reqVO.getIdList()) {
            reqVO.setId(id);
            // 校验任务存在
            Task task = checkTask(userId, reqVO.getId());
            ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
            if (instance == null) {
                throw exception(PROCESS_INSTANCE_NOT_EXISTS);
            }
            reqVO.setReason(HtmlUtil.filter(reqVO.getReason()));
            // 如果有审批附近，保存附件
            createExternalFile(reqVO.getId(), instance.getProcessInstanceId(),reqVO.getFileList(),reqVO.getImageList());
            // 更新负责人
            updateTaskAssignee(task.getId(), reqVO.getAssigneeUserId());
            // 更新任务拓展表为不通过
            taskExtMapper.updateByTaskId(
                    new BpmTaskExtDO().setTaskId(task.getId()).setReason(reqVO.getReason()));
        }

    }

    @Override
    public void updateTaskAssignee(String id, Long userId) {
        taskService.setAssignee(id, String.valueOf(userId));
    }

    public void createExternalFile(String taskId, String processInstanceId,
                                    List<ExternalFileInfo> fileList, List<ExternalFileInfo> imageList) {
        ExternalFileCreateBO externalFileCreateBO = new ExternalFileCreateBO().setTaskId(taskId)
                .setProcessInstanceId(processInstanceId).setFileList(fileList).setImageList(imageList);
        externalFileService.createExternalFile(externalFileCreateBO);
    }
    /**
     * 校验任务是否存在， 并且是否是分配给自己的任务
     *
     * @param userId 用户 id
     * @param taskId task id
     */
    private Task checkTask(Long userId, String taskId) {
        Task task = getTask(taskId);
        if (task == null) {
            throw exception(TASK_COMPLETE_FAIL_NOT_EXISTS);
        }
        if (!Objects.equals(userId, NumberUtils.parseLong(task.getAssignee()))) {
            throw exception(TASK_COMPLETE_FAIL_ASSIGN_NOT_SELF);
        }
        return task;
    }

    @Override
    public void createTaskExt(Task task) {
        BpmTaskExtDO taskExtDO =
                BpmTaskConvert.INSTANCE.convert2TaskExt(task).setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
        taskExtMapper.insert(taskExtDO);
    }

    @Override
    public void updateTaskExtComplete(Task task) {
        BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert2TaskExt(task)
                .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()) // 不设置也问题不大，因为 Complete 一般是审核通过，已经设置
                .setEndTime(LocalDateTime.now());
        taskExtMapper.updateByTaskId(taskExtDO);
    }

    @Override
    public void updateTaskExtCancel(String taskId) {
        // 需要在事务提交后，才进行查询。不然查询不到历史的原因
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {

            @Override
            public void afterCommit() {
                // 可能只是活动，不是任务，所以查询不到
                HistoricTaskInstance task = getHistoricTask(taskId);
                if (task == null) {
                    return;
                }

                // 如果任务拓展表已经是完成的状态，则跳过
                BpmTaskExtDO taskExt = taskExtMapper.selectByTaskId(taskId);
                if (taskExt == null) {
                    log.error("[updateTaskExtCancel][taskId({}) 查找不到对应的记录，可能存在问题]", taskId);
                    return;
                }
                // 如果已经是最终的结果，则跳过
                if (BpmProcessInstanceResultEnum.isEndResult(taskExt.getResult())) {
                    log.error("[updateTaskExtCancel][taskId({}) 处于结果({})，无需进行更新]", taskId, taskExt.getResult());
                    return;
                }

                // 更新任务
                taskExtMapper.updateById(new BpmTaskExtDO().setId(taskExt.getId()).setResult(BpmProcessInstanceResultEnum.CANCEL.getResult())
                        .setEndTime(LocalDateTime.now()).setReason(BpmProcessInstanceDeleteReasonEnum.translateReason(task.getDeleteReason())));
            }

        });
    }

    @Override
    public void updateTaskExtAssign(Task task) {
        BpmTaskExtDO taskExtDO = new BpmTaskExtDO().setAssigneeUserId(NumberUtils.parseLong(task.getAssignee())).setTaskId(task.getId());
        taskExtMapper.updateByTaskId(taskExtDO);
        // 发送通知。在事务提交时，批量执行操作，所以直接查询会无法查询到 ProcessInstance，所以这里是通过监听事务的提交来实现。
        // 屏蔽发送短信信息的通知（因为这里的逻辑会校验用户手机号）
//        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
//            @Override
//            public void afterCommit() {
//                ProcessInstance processInstance =
//                        processInstanceService.getProcessInstance(task.getProcessInstanceId());
//                AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId()));
//                messageService.sendMessageWhenTaskAssigned(
//                        BpmTaskConvert.INSTANCE.convert(processInstance, startUser, task));
//            }
//        });

    }

    @Override
    public List<BpmTaskTodoPageItemRespVO> getTodoTaskListByInstanceIds(Long userId, List<String> processInstanceIds) {
        // 查询待办任务
        TaskQuery taskQuery = taskService.createTaskQuery()
                .taskAssignee(String.valueOf(userId)) // 分配给自己
                .processInstanceIdIn(processInstanceIds)  // 根据流程定义ids过滤
                .orderByTaskCreateTime().desc(); // 创建时间倒序

        // 执行查询
        List<Task> tasks = taskQuery.list();

        if (CollUtil.isEmpty(tasks)) {
            return null;
        }

        // 获得 ProcessInstance Map
        Map<String, ProcessInstance> processInstanceMap = processInstanceService.getProcessInstanceMap(
                convertSet(tasks, Task::getProcessInstanceId));
        // 获得 User Map
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMapByIdsJoin(
                convertSet(processInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId())));
        // 拼接结果
        return BpmTaskConvert.INSTANCE.convertList1(tasks, processInstanceMap, userMap);
    }

    @Override
    public Long getIdByTaskIdAndProcessinstanceId(String sql) {

        return taskExtMapper.getIdByTaskIdAndProcessinstanceId(sql);
    }

    @Override
    public BpmTaskExtDO getBpmtaskext(Long remindId) {
        return taskExtMapper.getBpmtaskext(remindId);
    }

    @Override
    public Boolean getBatchApprovalStatus(Long userId, @Valid BpmTaskTodoPageReqVO pageVO) {
        // 查询待办任务
        TaskQuery taskQuery = taskService.createTaskQuery().taskAssignee(String.valueOf(userId)) // 分配给自己
                .orderByTaskCreateTime().desc(); // 创建时间倒序

        // 执行查询
        List<Task> tasks = taskQuery.list();
        if (CollUtil.isEmpty(tasks)) {
            return false;
        }
        tasks = tasks.stream().filter(task -> pageVO.getIdList().contains(task.getId())).collect(Collectors.toList());

        // 获得 ProcessInstance Map
        Map<String, ProcessInstance> processInstanceMap =
                processInstanceService.getProcessInstanceMap(convertSet(tasks, Task::getProcessInstanceId));
        // 获得 User Map
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMapByIdsJoin(
                convertSet(processInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId())));
        // 拼接结果
        List<BpmTaskTodoPageItemRespVO> bpmTaskTodoPageItemRespVOS = BpmTaskConvert.INSTANCE.convertList1(tasks, processInstanceMap, userMap);
        Set<String>  number = new HashSet<>();
        for (BpmTaskTodoPageItemRespVO RespVO : bpmTaskTodoPageItemRespVOS) {
            number.add(RespVO.getProcessInstance().getProcessDefinitionId());
        }
        if(number.size() == 1 || pageVO.getIdList().size()==1){
            return true;
        }else{
            return false;
        }

    }

    @Override
    @Transactional
    public void cancelTask(String processInstanceId) {
        QueryWrapper<BpmTaskExtDO> qw = new QueryWrapper<>();
        qw.lambda().eq(BpmTaskExtDO::getProcessInstanceId, processInstanceId);
        List<BpmTaskExtDO> bpmTaskExtDOS = taskExtMapper.selectList(qw);
        bpmTaskExtDOS.forEach(item -> updateTaskExtCancel(item.getTaskId()));
    }

    private Task getTask(String id) {
        return taskService.createTaskQuery().taskId(id).singleResult();
    }

    private HistoricTaskInstance getHistoricTask(String id) {
        return historyService.createHistoricTaskInstanceQuery().taskId(id).singleResult();
    }

}
